Stephan Tolksdorf: fixes the issue in the <atomic> header and adds corresponding tests. I've used macros to fall back to a user-provided default constructor if _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS (though I suspect that there won't be many users defining that macro). The tests use placement new to check that atomic values get properly zero-initialized. I had to modify the atomic_is_lock_free test, because default initialization of an object of const type 'const A' (aka 'const atomic<int>') requires a user-provided default constructor. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@180945 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/CREDITS.TXT b/CREDITS.TXT index 61b3542..34a901f 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT
@@ -48,6 +48,10 @@ E: kyrtzidis@apple.com D: Bug fixes. +N: Bruce Mitchener, Jr. +E: bruce.mitchener@gmail.com +D: Emscripten-related changes. + N: Michel Morin E: mimomorin@gmail.com D: Minor patches to is_convertible. @@ -78,6 +82,10 @@ E: joerg@NetBSD.org D: NetBSD port. +N: Stephan Tolksdorf +E: st@quanttec.com +D: Minor <atomic> fix + N: Michael van der Westhuizen E: r1mikey at gmail dot com @@ -93,7 +101,3 @@ E: jyasskin@gmail.com E: jyasskin@google.com D: Linux fixes. - -N: Bruce Mitchener, Jr. -E: bruce.mitchener@gmail.com -D: Emscripten-related changes.
diff --git a/include/__config b/include/__config index 389b6c4..7923f2f 100644 --- a/include/__config +++ b/include/__config
@@ -216,7 +216,9 @@ # define _LIBCPP_NORETURN __attribute__ ((noreturn)) #endif +#if !(__has_feature(cxx_defaulted_functions)) #define _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#endif // !(__has_feature(cxx_defaulted_functions)) #if !(__has_feature(cxx_deleted_functions)) #define _LIBCPP_HAS_NO_DELETED_FUNCTIONS @@ -422,6 +424,12 @@ #define _LIBCPP_CONSTEXPR constexpr #endif +#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#define _LIBCPP_DEFAULT {} +#else +#define _LIBCPP_DEFAULT = default; +#endif + #ifdef __GNUC__ #define _NOALIAS __attribute__((__malloc__)) #else diff --git a/include/atomic b/include/atomic index db67e76..f6ab1cb 100644 --- a/include/atomic +++ b/include/atomic
@@ -622,7 +622,12 @@ {return __c11_atomic_compare_exchange_strong(&__a_, &__e, __d, __m, __m);} _LIBCPP_INLINE_VISIBILITY - __atomic_base() _NOEXCEPT {} // = default; +#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS + __atomic_base() _NOEXCEPT = default; +#else + __atomic_base() _NOEXCEPT : __a_() {} +#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __a_(__d) {} #ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS @@ -645,7 +650,7 @@ { typedef __atomic_base<_Tp, false> __base; _LIBCPP_INLINE_VISIBILITY - __atomic_base() _NOEXCEPT {} // = default; + __atomic_base() _NOEXCEPT _LIBCPP_DEFAULT _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __base(__d) {} @@ -726,7 +731,7 @@ { typedef __atomic_base<_Tp> __base; _LIBCPP_INLINE_VISIBILITY - atomic() _NOEXCEPT {} // = default; + atomic() _NOEXCEPT _LIBCPP_DEFAULT _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR atomic(_Tp __d) _NOEXCEPT : __base(__d) {} @@ -746,7 +751,7 @@ { typedef __atomic_base<_Tp*> __base; _LIBCPP_INLINE_VISIBILITY - atomic() _NOEXCEPT {} // = default; + atomic() _NOEXCEPT _LIBCPP_DEFAULT _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR atomic(_Tp* __d) _NOEXCEPT : __base(__d) {} @@ -1367,7 +1372,12 @@ {__c11_atomic_store(&__a_, false, __m);} _LIBCPP_INLINE_VISIBILITY - atomic_flag() _NOEXCEPT {} // = default; +#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS + atomic_flag() _NOEXCEPT = default; +#else + atomic_flag() _NOEXCEPT : __a_() {} +#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS + _LIBCPP_INLINE_VISIBILITY atomic_flag(bool __b) _NOEXCEPT : __a_(__b) {} diff --git a/test/atomics/atomics.flag/default.pass.cpp b/test/atomics/atomics.flag/default.pass.cpp index 489e3d2..5c077b0 100644 --- a/test/atomics/atomics.flag/default.pass.cpp +++ b/test/atomics/atomics.flag/default.pass.cpp
@@ -14,9 +14,18 @@ // atomic_flag() = default; #include <atomic> +#include <new> #include <cassert> int main() { std::atomic_flag f; + + { + typedef std::atomic_flag A; + _ALIGNAS_TYPE(A) char storage[sizeof(A)] = {1}; + A& zero = *new (storage) A(); + assert(!zero.test_and_set()); + zero.~A(); + } } diff --git a/test/atomics/atomics.types.generic/address.pass.cpp b/test/atomics/atomics.types.generic/address.pass.cpp index 1cfdef5..af9826f 100644 --- a/test/atomics/atomics.types.generic/address.pass.cpp +++ b/test/atomics/atomics.types.generic/address.pass.cpp
@@ -66,6 +66,7 @@ // }; #include <atomic> +#include <new> #include <type_traits> #include <cassert> @@ -112,6 +113,13 @@ assert(obj == T(5*sizeof(X))); assert((obj -= std::ptrdiff_t(3)) == T(2*sizeof(X))); assert(obj == T(2*sizeof(X))); + + { + _ALIGNAS_TYPE(A) char storage[sizeof(A)] = {23}; + A& zero = *new (storage) A(); + assert(zero == 0); + zero.~A(); + } } template <class A, class T> diff --git a/test/atomics/atomics.types.generic/bool.pass.cpp b/test/atomics/atomics.types.generic/bool.pass.cpp index f6379dc..80e5665 100644 --- a/test/atomics/atomics.types.generic/bool.pass.cpp +++ b/test/atomics/atomics.types.generic/bool.pass.cpp
@@ -50,6 +50,7 @@ // typedef atomic<bool> atomic_bool; #include <atomic> +#include <new> #include <cassert> int main() @@ -219,4 +220,11 @@ assert((obj = true) == true); assert(obj == true); } + { + typedef std::atomic<bool> A; + _ALIGNAS_TYPE(A) char storage[sizeof(A)] = {1}; + A& zero = *new (storage) A(); + assert(zero == false); + zero.~A(); + } } diff --git a/test/atomics/atomics.types.generic/integral.pass.cpp b/test/atomics/atomics.types.generic/integral.pass.cpp index fc678bc..26caa50 100644 --- a/test/atomics/atomics.types.generic/integral.pass.cpp +++ b/test/atomics/atomics.types.generic/integral.pass.cpp
@@ -85,6 +85,7 @@ // }; #include <atomic> +#include <new> #include <cassert> template <class A, class T> @@ -143,6 +144,13 @@ assert(obj == T(7)); assert((obj ^= T(0xF)) == T(8)); assert(obj == T(8)); + + { + _ALIGNAS_TYPE(A) char storage[sizeof(A)] = {23}; + A& zero = *new (storage) A(); + assert(zero == 0); + zero.~A(); + } } template <class A, class T> diff --git a/test/atomics/atomics.types.operations/atomics.types.operations.req/atomic_is_lock_free.pass.cpp b/test/atomics/atomics.types.operations/atomics.types.operations.req/atomic_is_lock_free.pass.cpp index 4b09c38..4071989 100644 --- a/test/atomics/atomics.types.operations/atomics.types.operations.req/atomic_is_lock_free.pass.cpp +++ b/test/atomics/atomics.types.operations/atomics.types.operations.req/atomic_is_lock_free.pass.cpp
@@ -24,10 +24,10 @@ test() { typedef std::atomic<T> A; - const A ct; - bool b1 = std::atomic_is_lock_free(&ct); - const volatile A cvt; - bool b2 = std::atomic_is_lock_free(&cvt); + A t; + bool b1 = std::atomic_is_lock_free(static_cast<const A*>(&t)); + volatile A vt; + bool b2 = std::atomic_is_lock_free(static_cast<const volatile A*>(&vt)); } struct A